<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title>DataSource Tests</title>
<script type="text/javascript" src="../../../build/yui/yui.js"></script>
<script type="text/javascript" src="../../../build/datasource/datasource-debug.js"></script>
</head>

<body class="yui3-skin-sam">
<h1>DataSource Tests</h1>
<p><input type="button" value="Run Tests" id="btnRun" disabled="true" /></p>

<script type="text/javascript">

(function() {
    YUI({
        base: "../../../build/",
        filter: "raw",
        logInclude:{"TestRunner":true,"datasource":true},
        useConsole: true
    }).use("dump", "test", "console", "io-base", "cache", "base", "plugin", "json", "datatype", "dataschema", "datasource", function(Y) {

        var ASSERT = Y.Assert,
            ARRAYASSERT = Y.ArrayAssert,
            OBJECTASSERT = Y.ObjectAssert,
            BTNRUN = Y.one("#btnRun"),
            WAITTIMEOUT = 5000; // On a slow connection set to 5000

        // Set up the page
        
        BTNRUN.set("disabled", false);
        Y.on("click", function() {
            Y.Test.Runner.run();
        }, BTNRUN);
        var myConsole = new Y.Console().render();
 
        var testClass = new Y.Test.Case({
            name: "Class Tests",
        
            testConstructor: function() {
                var ds = new Y.DataSource.Local();
                ASSERT.areSame((ds instanceof Y.Base), true, "Expected DataSource.Base instance.");
                ASSERT.areSame((ds instanceof Y.DataSource.Local), true, "Expected DataSource.Local instance.");
            },

            testConstructorIO: function() {
                var ds = new Y.DataSource.IO();
                ASSERT.areSame((ds instanceof Y.Base), true, "Expected Base instance.");
                ASSERT.areSame((ds instanceof Y.DataSource.Local), true, "Expected DataSource.Local instance.");
                ASSERT.areSame((ds instanceof Y.DataSource.IO), true, "Expected DataSource.IO instance.");
            }
        });
        
        var testLocal = new Y.Test.Case({
            name: "DataSource.Local Tests",

            testLocalDefaults: function() {
                var ds = new Y.DataSource.Local({
                    source: ["a","b","c","d"]
                });

                var handler = Y.Mock();
                Y.Mock.expect(handler,{
                    method: "handleSuccess",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isUndefined(e.request, "request: Expected undefined request.");
                        ARRAYASSERT.itemsAreSame(["a","b","c","d"], e.response.results, "Expected live array.");
                    })]
                });

                ds.sendRequest({
                    callback: {
                        success: handler.handleSuccess,
                        failure: function(e) {
                            ASSERT.fail("IO failure case.");
                        }
                    }
                });
                
                Y.Mock.verify(handler);
            },

            testLocalEvents: function() {
                var ds = new Y.DataSource.Local({
                    source: ["a","b","c","d"]
                });
                
                var handler = Y.Mock();
                Y.Mock.expect(handler,{
                    method: "handleRequest",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isNumber(e.tId, "request: Expected transaction ID.");
                        ASSERT.areSame("a", e.request, "request: Expected request.");
                        ASSERT.areSame("callback", e.callback, "request: Expected callback.");
                    })]
                });
                ds.on("request", handler.handleRequest);

                Y.Mock.expect(handler,{
                    method: "handleData",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isNumber(e.tId, "data: Expected transaction ID.");
                        ASSERT.areSame("a", e.request, "data: Expected request.");
                        ASSERT.areSame("callback", e.callback, "data: Expected callback.");
                        ASSERT.isArray(e.data, "data: Expected raw data.");
                    })]
                });
                ds.on("data", handler.handleData);
                
                Y.Mock.expect(handler,{
                    method: "handleResponse",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isNumber(e.tId, "response: Expected transaction ID.");
                        ASSERT.areSame("a", e.request, "response: Expected request.");
                        ASSERT.areSame("callback", e.callback, "response: Expected callback.");
                        ASSERT.isArray(e.data, "response: Expected raw data.");
                        ASSERT.isObject(e.response, "response: Expected normalized response object.");
                        ASSERT.isArray(e.response.results, "response: Expected parsed results.");
                        ASSERT.isObject(e.response.meta, "response: Expected parsed meta data.");
                    })]
                });
                ds.on("response", handler.handleResponse);

                ds.sendRequest({
                    request: "a",
                    callback: "callback"
                });
                Y.Mock.verify(handler);
            },

            testLocalError: function() {
                var ds = new Y.DataSource.Local({
                    source: ["a","b","c","d"]
                });

                var handler = Y.Mock();
                Y.Mock.expect(handler,{
                    method: "handleError",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isNumber(e.tId, "error: Expected transaction ID.");
                        ASSERT.areSame("a", e.request, "error: Expected request.");
                        ASSERT.areSame("callback", e.callback, "error: Expected callback.");
                        ASSERT.isObject(e.response, "error: Expected normalized response object.");
                        ASSERT.isObject(e.error, "error: Expected error.");
                    })]
                });
                ds.on("error", handler.handleError);

                ds.set("source", undefined);
                ds.sendRequest({
                    request: "a",
                    callback: "callback"
                });
                this.wait(function(){Y.Mock.verify(handler);}, WAITTIMEOUT);
            }
        });

        var testIO = new Y.Test.Case({
            name: "DataSource.IO Tests",

            testIODefaults: function() {
                var ds = new Y.DataSource.IO({
                    source: "./php/ysearch_json_madonna.php"
                });

                var handler = Y.Mock();
                Y.Mock.expect(handler,{
                    method: "handleSuccess",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isNull(e.request, "Expected null request.");
                        ASSERT.isObject(e.response, "Expected response object.");
                        OBJECTASSERT.ownsKeys({tId:null,request:null,data:null,response:null,callback:null}, e, "Expected all properties.");
                    })]
                });

                ds.sendRequest({
                    request: null,
                    callback: {
                        success: handler.handleSuccess,
                        failure: function(e) {
                            ASSERT.fail("IO failure case.");
                        }
                    }
                });

                this.wait(function(){Y.Mock.verify(handler);}, WAITTIMEOUT);
            },

            testIOConfig: function() {
                var ds = new Y.DataSource.IO({
                    source: "x",
                    ioConfig: {
                        method: "POST",
                        data: "foo=bar",
                        timeout: 1
                    }
                });

                var handler = Y.Mock();
                Y.Mock.expect(handler,{
                    method: "handleFailure",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isObject(e.error, "Expected error from timeout.");
                        ASSERT.isNull(e.request, "Expected null request.");
                        ASSERT.isObject(e.response, "Expected response object.");
                        OBJECTASSERT.ownsKeys({tId:null,request:null,data:null,response:null,callback:null}, e, "Expected all properties.");
                    })]
                });

                ds.sendRequest({
                    request: null,
                    callback: {
                        success: function(e) {
                            ASSERT.fail("IO failure case.");
                        },
                        failure: handler.handleFailure
                    }
                });

                this.wait(function(){Y.Mock.verify(handler);}, WAITTIMEOUT);
            },

            testIOPost: function() {
                var ds = new Y.DataSource.IO({
                    source: "./php/ysearch_json_madonna.php"
                });

                var handler = Y.Mock();
                Y.Mock.expect(handler,{
                    method: "handleSuccess",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isUndefined(e.request, "Expected undefined request.");
                        ASSERT.isObject(e.response, "Expected response object.");
                        OBJECTASSERT.ownsKeys({tId:null,request:null,data:null,response:null,callback:null}, e, "Expected all properties.");
                    })]
                });

                ds.sendRequest({
                    callback: {
                        success: handler.handleSuccess,
                        failure: function(e) {
                            ASSERT.fail("IO failure case.");
                        }
                    },
                    cfg: {
                        method: "POST",
                        data: "foo=bar"
                    }
                });

                this.wait(function(){Y.Mock.verify(handler);}, WAITTIMEOUT);
            },

            testIOEvents: function() {
                var ds = new Y.DataSource.IO({
                    source: "./php/ysearch_json_madonna.php"
                });
                ds.plug({fn: Y.Plugin.DataSourceJSONSchema, cfg: {
                    schema: {
                        resultListLocator: "ResultSet.Result",
                        resultFields: ["Title"]
                    }
                }});

                var handler = Y.Mock();
                Y.Mock.expect(handler,{
                    method: "handleRequest",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isNumber(e.tId, "request: Expected transaction ID.");
                        ASSERT.isUndefined(e.request, "request: Expected undefined request.");
                        ASSERT.areSame("callback", e.callback, "request: Expected callback.");
                    })]
                });
                ds.on("request", handler.handleRequest);

                Y.Mock.expect(handler,{
                    method: "handleData",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isNumber(e.tId, "data: Expected transaction ID.");
                        ASSERT.isUndefined(e.request, "data: Expected undefined request.");
                        ASSERT.areSame("callback", e.callback, "data: Expected callback.");
                        ASSERT.isObject(e.data, "data: Expected raw data.");
                    })]
                });
                ds.on("data", handler.handleData);

                Y.Mock.expect(handler,{
                    method: "handleResponse",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isNumber(e.tId, "response: Expected transaction ID.");
                        ASSERT.isUndefined(e.request, "response: Expected undefined request.");
                        ASSERT.areSame("callback", e.callback, "response: Expected callback.");
                        ASSERT.isObject(e.data, "response: Expected raw data.");
                        ASSERT.isObject(e.response, "response: Expected normalized response object.");
                        ASSERT.isArray(e.response.results, "response: Expected parsed results.");
                        ASSERT.isObject(e.response.meta, "response: Expected parsed meta data.");
                    })]
                });
                ds.on("response", handler.handleResponse);

                ds.sendRequest({
                    callback: "callback"
                });
                this.wait(function(){Y.Mock.verify(handler);}, WAITTIMEOUT);
            },

            testIOError: function() {
                var ds = new Y.DataSource.IO({
                    source: "./php/ysearch_json_madonna.php"
                });
                ds.plug({fn: Y.Plugin.DataSourceJSONSchema, cfg: {
                    schema: {
                        resultListLocator: "ResultSet.Result",
                        resultFields: ["Title"]
                    }
                }});

                var handler = Y.Mock();
                Y.Mock.expect(handler,{
                    method: "handleError",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isNumber(e.tId, "error: Expected transaction ID.");
                        ASSERT.areSame("a", e.request, "error: Expected request.");
                        ASSERT.areSame("callback", e.callback, "error: Expected callback.");
                        ASSERT.isObject(e.data, "error: Expected raw data.");
                        ASSERT.isObject(e.response, "error: Expected normalized response object.");
                        ASSERT.isObject(e.error, "error: Expected error.");
                    })]
                });
                ds.on("error", handler.handleError);

                ds.set("source", "foo");
                ds.sendRequest({
                    request: "a",
                    callback: "callback"
                });
                this.wait(function(){Y.Mock.verify(handler);}, WAITTIMEOUT);
            }
        });

        var testGet = new Y.Test.Case({
            name: "DataSource.Get Tests",

            testGetDefaults: function() {
                var ds = new Y.DataSource.Get({
                    source: "http://query.yahooapis.com/v1/public/yql?format=json&"
                });

                var handler = Y.Mock();
                Y.Mock.expect(handler,{
                    method: "handleSuccess",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.areSame("q=select%20*%20from%20search.web%20where%20query%3D%22pizza%22", e.request, "Expected same request.");
                        ASSERT.isObject(e.response, "Expected response object.");
                        OBJECTASSERT.ownsKeys({tId:null,request:null,data:null,response:null,callback:null}, e, "Expected all properties.");
                    })]
                });

                ds.sendRequest({
                    request: "q=select%20*%20from%20search.web%20where%20query%3D%22pizza%22",
                    callback: {
                        success: handler.handleSuccess,
                        failure: function(e) {
                            ASSERT.fail("Get failure case.");
                        }
                    }
                });

                this.wait(function(){Y.Mock.verify(handler);}, WAITTIMEOUT);
            },

            testGetEvents: function() {
                var ds = new Y.DataSource.Get({
                    source: "http://query.yahooapis.com/v1/public/yql?format=json&"
                });
                ds.plug({fn: Y.Plugin.DataSourceJSONSchema, cfg: {
                    schema: {
                        resultListLocator: "query.results.result",
                        resultFields: ["title"]
                    }
                }});

                var handler = Y.Mock();
                Y.Mock.expect(handler,{
                    method: "handleRequest",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isNumber(e.tId, "request: Expected transaction ID.");
                        ASSERT.areSame("q=select%20*%20from%20search.web%20where%20query%3D%22pizza%22", e.request, "Expected same request.");
                        ASSERT.areSame("callback", e.callback, "request: Expected callback.");
                    })]
                });
                ds.on("request", handler.handleRequest);

                Y.Mock.expect(handler,{
                    method: "handleData",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isNumber(e.tId, "data: Expected transaction ID.");
                        ASSERT.areSame("q=select%20*%20from%20search.web%20where%20query%3D%22pizza%22", e.request, "Expected same request.");
                        ASSERT.areSame("callback", e.callback, "data: Expected callback.");
                        ASSERT.isObject(e.data, "data: Expected raw data.");
                    })]
                });
                ds.on("data", handler.handleData);

                Y.Mock.expect(handler,{
                    method: "handleResponse",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isNumber(e.tId, "response: Expected transaction ID.");
                        ASSERT.areSame("q=select%20*%20from%20search.web%20where%20query%3D%22pizza%22", e.request, "Expected same request.");
                        ASSERT.areSame("callback", e.callback, "response: Expected callback.");
                        ASSERT.isObject(e.data, "response: Expected raw data.");
                        ASSERT.isObject(e.response, "response: Expected normalized response object.");
                        ASSERT.isArray(e.response.results, "response: Expected parsed results.");
                        ASSERT.isObject(e.response.meta, "response: Expected parsed meta data.");
                    })]
                });
                ds.on("response", handler.handleResponse);

                ds.sendRequest({
                    request: "q=select%20*%20from%20search.web%20where%20query%3D%22pizza%22",
                    callback: "callback"
                });
                this.wait(function(){Y.Mock.verify(handler);}, WAITTIMEOUT);
            },

            // Only FF can detect error state in Get Utility...
            testGetError: (Y.UA.gecko) ? function() {
                var ds = new Y.DataSource.Get({
                    source: "http://query.yahooapis.com/v1/public/yql?format=json&"
                });
                ds.plug({fn: Y.Plugin.DataSourceJSONSchema, cfg: {
                    schema: {
                        resultListLocator: "query.results.result",
                        resultFields: ["title"]
                    }
                }});

                var handler = Y.Mock();
                Y.Mock.expect(handler,{
                    method: "handleError",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isNumber(e.tId, "error: Expected transaction ID.");
                        ASSERT.areSame("a", e.request, "error: Expected request.");
                        ASSERT.areSame("callback", e.callback, "error: Expected callback.");
                        ASSERT.isUndefined(e.data, "error: Expected undefined data.");
                        ASSERT.isObject(e.response, "error: Expected normalized response object.");
                        ASSERT.isObject(e.error, "error: Expected error.");
                    })]
                });
                ds.on("error", handler.handleError);

                ds.set("source", "foo");
                ds.sendRequest({
                    request: "a",
                    callback: "callback"
                });
                this.wait(function(){Y.Mock.verify(handler);}, WAITTIMEOUT);
            } : function(){}
        });

        var testFunction = new Y.Test.Case({
            name: "DataSource.Function Tests",

            testFunctionDefaults: function() {
                var ds = new Y.DataSource.Function({
                    source: function() {
                        return [{type:"a",age:0,name:"c"},{type:"d",age:1,name:"f"},{type:"g",age:-1,name:"i"}];
                    }
                });

                var handler = Y.Mock();
                Y.Mock.expect(handler,{
                    method: "handleSuccess",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.areSame("foo", e.request, "Expected same request.");
                        ASSERT.isObject(e.response, "Expected response object.");
                        OBJECTASSERT.ownsKeys({tId:null,request:null,data:null,response:null,callback:null}, e, "Expected all properties.");
                    })]
                });

                ds.sendRequest({
                    request: "foo",
                    callback: {
                        success: handler.handleSuccess,
                        failure: function(e) {
                            ASSERT.fail("Function failure case.");
                        }
                    }
                });

                this.wait(function(){Y.Mock.verify(handler);}, WAITTIMEOUT);
            },

            testFunctionEvents: function() {
                var ds = new Y.DataSource.Function({
                    source: function() {
                        return [{type:"a",age:0,name:"c"},{type:"d",age:1,name:"f"},{type:"g",age:-1,name:"i"}];
                    }
                });
                ds.plug({fn: Y.Plugin.DataSourceArraySchema, cfg: {
                    schema: {
                        resultFields: ["type", "name"]
                    }
                }});

                var handler = Y.Mock();
                Y.Mock.expect(handler,{
                    method: "handleRequest",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isNumber(e.tId, "request: Expected transaction ID.");
                        ASSERT.areSame("foo", e.request, "Expected same request.");
                        ASSERT.areSame("callback", e.callback, "request: Expected callback.");
                    })]
                });
                ds.on("request", handler.handleRequest);

                Y.Mock.expect(handler,{
                    method: "handleData",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isNumber(e.tId, "data: Expected transaction ID.");
                        ASSERT.areSame("foo", e.request, "Expected same request.");
                        ASSERT.areSame("callback", e.callback, "data: Expected callback.");
                        ASSERT.isObject(e.data, "data: Expected raw data.");
                    })]
                });
                ds.on("data", handler.handleData);

                Y.Mock.expect(handler,{
                    method: "handleResponse",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isNumber(e.tId, "response: Expected transaction ID.");
                        ASSERT.areSame("foo", e.request, "Expected same request.");
                        ASSERT.areSame("callback", e.callback, "response: Expected callback.");
                        ASSERT.isObject(e.data, "response: Expected raw data.");
                        ASSERT.isObject(e.response, "response: Expected normalized response object.");
                        ASSERT.isArray(e.response.results, "response: Expected parsed results.");
                        ASSERT.isObject(e.response.meta, "response: Expected parsed meta data.");
                    })]
                });
                ds.on("response", handler.handleResponse);

                ds.sendRequest({
                    request: "foo",
                    callback: "callback"
                });
                this.wait(function(){Y.Mock.verify(handler);}, WAITTIMEOUT);
            },

            testFunctionError: function() {
                var ds = new Y.DataSource.Function({
                    source: "foo"
                });
                ds.plug({fn: Y.Plugin.DataSourceArraySchema, cfg: {
                    schema: {
                        resultFields: ["type", "name"]
                    }
                }});

                var handler = Y.Mock();
                Y.Mock.expect(handler,{
                    method: "handleError",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isNumber(e.tId, "error: Expected transaction ID.");
                        ASSERT.areSame("a", e.request, "error: Expected request.");
                        ASSERT.areSame("callback", e.callback, "error: Expected callback.");
                        ASSERT.isUndefined(e.data, "error: Expected undefined data.");
                        ASSERT.isObject(e.response, "error: Expected normalized response object.");
                        ASSERT.isObject(e.error, "error: Expected error.");
                    })]
                });
                ds.on("error", handler.handleError);

                ds.sendRequest({
                    request: "a",
                    callback: "callback"
                });
                this.wait(function(){Y.Mock.verify(handler);}, WAITTIMEOUT);
            },
            
            testFunctionException: function() {
                var ds = new Y.DataSource.Function({
                    source: function() {
                        throw new Error("myException")
                    }
                });
                ds.plug({fn: Y.Plugin.DataSourceArraySchema, cfg: {
                    schema: {
                        resultFields: ["type", "name"]
                    }
                }});

                var handler = Y.Mock();
                Y.Mock.expect(handler,{
                    method: "handleError",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isNumber(e.tId, "error: Expected transaction ID.");
                        ASSERT.areSame("a", e.request, "error: Expected request.");
                        ASSERT.areSame("callback", e.callback, "error: Expected callback.");
                        ASSERT.isUndefined(e.data, "error: Expected undefined data.");
                        ASSERT.isObject(e.response, "error: Expected normalized response object.");
                        ASSERT.isObject(e.error, "error: Expected error.");
                        ASSERT.areSame("myException", e.error.message, "error: Expected message.");
                    })]
                });
                ds.on("error", handler.handleError);

                ds.sendRequest({
                    request: "a",
                    callback: "callback"
                });
                this.wait(function(){Y.Mock.verify(handler);}, WAITTIMEOUT);
            }
        });

        var testDataSchemaPlugin = new Y.Test.Case({
            name: "DataSource DataSchema Plugin Tests",

            testJSONSchema: function() {
                var ds = new Y.DataSource.IO({
                    source: "./php/ysearch_json_madonna.php"
                });
                ds.plug({fn: Y.Plugin.DataSourceJSONSchema, cfg: {
                    schema: {
                        resultListLocator: "ResultSet.Result",
                        resultFields: ["Title"]
                    }
                }});

                var handler = Y.Mock();
                Y.Mock.expect(handler,{
                    method: "handleSuccess",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isUndefined(e.request, "Expected undefined request.");
                        ASSERT.isObject(e.response, "Expected normalized response object.");
                        ASSERT.isArray(e.response.results, "Expected results array.");
                        ASSERT.areSame(10, e.response.results.length, "Expected 10 results.")
                        ASSERT.isNotUndefined(e.response.results[0].Title, "Expected Title property")
                    })]
                });

                ds.sendRequest({
                    callback: {
                        success: Y.bind(handler.handleSuccess, this),
                        failure: Y.bind(function(e) {
                            ASSERT.fail("IO failure case.");
                        }, this)
                    }
                });

                this.wait(function(){Y.Mock.verify(handler);}, WAITTIMEOUT);
            },

            testXMLSchema: function() {
                var ds = new Y.DataSource.IO({
                    source: "./php/ysearch_xml_madonna.php"
                });
                ds.plug({fn: Y.Plugin.DataSourceXMLSchema, cfg: {
                    schema: {
                        resultListLocator: "result",
                        resultFields: [{key:"title", locator:"*[local-name() ='title']"}]
                    }
                }});

                var handler = Y.Mock();
                Y.Mock.expect(handler,{
                    method: "handleSuccess",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isUndefined(e.request, "Expected undefined request.");
                        ASSERT.isObject(e.response, "Expected normalized response object.");
                        ASSERT.isArray(e.response.results, "Expected results array.");
                        ASSERT.areSame(10, e.response.results.length, "Expected 10 results.")
                        ASSERT.isString(e.response.results[0].title, "Expected title.")
                    })]
                });

                ds.sendRequest({
                    callback: {
                        success: Y.bind(handler.handleSuccess, this),
                        failure: Y.bind(function(e) {
                            ASSERT.fail("IO failure case.");
                        }, this)
                    }
                });

                this.wait(function(){Y.Mock.verify(handler);}, WAITTIMEOUT);
            },

            testArraySchema: function() {
                var ds = new Y.DataSource.Local({
                    source: [{type:"a",age:0,name:"c"},{type:"d",age:1,name:"f"},{type:"g",age:-1,name:"i"}]
                });
                ds.plug({fn: Y.Plugin.DataSourceArraySchema, cfg: {
                    schema: {
                        resultFields: ["type", "name"]
                    }
                }});

                var handler = Y.Mock();
                Y.Mock.expect(handler,{
                    method: "handleSuccess",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isUndefined(e.request, "Expected undefined request.");
                        ASSERT.isObject(e.response, "Expected normalized response object.");
                        ASSERT.isArray(e.response.results, "Expected results array.");
                        ASSERT.areSame(3, e.response.results.length, "Expected 3 results.")
                        ASSERT.areSame("a", e.response.results[0].type, "Expected first type.");
                        ASSERT.areSame("g", e.response.results[2].type, "Expected last type.");
                        ASSERT.areSame("c", e.response.results[0].name, "Expected first name.");
                        ASSERT.areSame("i", e.response.results[2].name, "Expected last name.");
                        ASSERT.isUndefined(e.response.results[0].age, "Expected no age on first result.");
                        ASSERT.isUndefined(e.response.results[2].age, "Expected no age on last result.");
                    })]
                });

                ds.sendRequest({
                    callback: {
                        success: Y.bind(handler.handleSuccess, this),
                        failure: Y.bind(function(e) {
                            ASSERT.fail("Local failure case.");
                        }, this)
                    }
                });

                this.wait(function(){Y.Mock.verify(handler);}, WAITTIMEOUT);
            },

            testTextSchema: function() {
                var ds = new Y.DataSource.Local({
                    source: "foo\t0\tabc\nbar\t1\tdef\nbat\t-1\tghi"
                });
                ds.plug({fn: Y.Plugin.DataSourceTextSchema, cfg: {
                    schema: {
                        resultDelimiter: "\n",
                        fieldDelimiter: "\t",
                        resultFields: [{key:"type"}, {key:"age", parser:"number"}, "name"]
                    }
                }});

                var handler = Y.Mock();
                Y.Mock.expect(handler,{
                    method: "handleSuccess",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isUndefined(e.request, "Expected undefined request.");
                        ASSERT.isObject(e.response, "Expected normalized response object.");
                        ASSERT.isArray(e.response.results, "Expected results array.");
                        ASSERT.areSame(3, e.response.results.length, "Expected 3 results.")
                        ASSERT.areSame("foo", e.response.results[0].type, "Expected first type.");
                        ASSERT.areSame("bat", e.response.results[2].type, "Expected last type.");
                        ASSERT.areSame(0, e.response.results[0].age, "Expected first age.");
                        ASSERT.areSame(-1, e.response.results[2].age, "Expected last age.");
                        ASSERT.areSame("abc", e.response.results[0].name, "Expected first name.");
                        ASSERT.areSame("ghi", e.response.results[2].name, "Expected last name.");
                    })]
                });

                ds.sendRequest({
                    callback: {
                        success: Y.bind(handler.handleSuccess, this),
                        failure: Y.bind(function(e) {
                            ASSERT.fail("Local failure case.");
                        }, this)
                    }
                });

                this.wait(function(){Y.Mock.verify(handler);}, WAITTIMEOUT);
            },

            testSchemaError: function() {
                var ds = new Y.DataSource.IO({
                    source: "./php/ysearch_json_madonna.php"
                });
                ds.plug({fn: Y.Plugin.DataSourceJSONSchema});

                var handler = Y.Mock();
                Y.Mock.expect(handler,{
                    method: "handleFailure",
                    args: [Y.Mock.Value(function(e){
                        ASSERT.isObject(e.response, "Expected normalized response object.");
                        ASSERT.isObject(e.error, "Expected response error.");
                    })]
                });

                ds.sendRequest({
                    callback: {
                        success: Y.bind(function(e) {
                            ASSERT.fail("IO failure case.");
                        }, this),
                        failure: Y.bind(handler.handleFailure, this)
                    }
                });

                this.wait(function(){Y.Mock.verify(handler);}, WAITTIMEOUT);
            }
        });
        
        var testCaching = new Y.Test.Case({
            name: "DataSource Caching Tests",

            testCacheDefaultMax: function() {
                var ds = new Y.DataSource.Local();
                ds.plug(Y.Plugin.DataSourceCache);
                ASSERT.areSame((ds.cache instanceof Y.Cache), true, "Expected Cache instance.");
                ASSERT.areSame(ds.cache.get("max"), 0, "Expected 0 max in Cache.");
            },

            testCacheInitMax: function() {
                var ds = new Y.DataSource.Local();
                ds.plug({fn:Y.Plugin.DataSourceCache, cfg:{max:3}});
                ASSERT.areSame((ds.cache instanceof Y.Cache), true, "Expected Cache instance.");
                ASSERT.areSame(ds.cache.get("max"), 3, "Expected 3 max in Cache.");
            },

            testCacheSetMax: function() {
                var ds = new Y.DataSource.Local();
                ds.plug({fn:Y.Plugin.DataSourceCache});
                ds.cache.set("max", 5);
                ASSERT.areSame((ds.cache instanceof Y.Cache), true, "Expected Cache instance.");
                ASSERT.areSame(ds.cache.get("max"), 5, "Expected 5 max in Cache.");
            },
            
            testLocalCache: function() {
                var ds = new Y.DataSource.Local({
                        source: ["a","b","c","d"]
                    });
                ds.plug({fn:Y.Plugin.DataSourceCache, cfg:{max:3}});

                ds.sendRequest({request:"a"});
                ds.sendRequest({request:"b"});
                ds.sendRequest({request:"c"});

                ds.on("data", function(e) {
                    
                });

                ds.sendRequest({request:"a"});
                ds.sendRequest({request:"b"});
                ds.sendRequest({request:"c", callback:{success:function(e){
                    ASSERT.isInstanceOf(Date, e.cached);
                }}});
            },

            testLocalCacheUnplug: function() {
                var ds = new Y.DataSource.Local({
                        source: ["a","b","c","d"]
                    });
                ds.plug({fn:Y.Plugin.DataSourceCache, cfg:{max:3}});

                ds.sendRequest({request:"a"});

                ds.cache.on("retrieve", function(e) {
                    ASSERT.fail("Cache is unset -- 'retrieve' event is unexpected");
                });

                ds.unplug("cache");
                ds.sendRequest({request:"a"});
            }
        });

        var testPolling = new Y.Test.Case({
            name: "DataSource Polling Tests",

            testClass: function() {
                var ds = new Y.DataSource.Local();
                ASSERT.isNotUndefined((ds.setInterval), "Expected setInterval() method on DataSource.Local.");
                ASSERT.isNotUndefined((ds.clearInterval), "Expected clearInterval() method on DataSource.Local.");

                ds = new Y.DataSource.IO();
                ASSERT.isNotUndefined((ds.setInterval), "Expected setInterval() method on DataSource.IO.");
                ASSERT.isNotUndefined((ds.clearInterval), "Expected clearInterval() method on DataSource.IO.");
            },

            testSetAndClear: function() {
                var ds = new Y.DataSource.Local();
                
                var handler = Y.Mock();
                Y.Mock.expect(handler,{
                    method: "handleSuccess",
                    args: [Y.Mock.Value.Any],
                    callCount: 3
                });

                var id = ds.setInterval(500, {
                    callback: {
                        success: handler.handleSuccess,
                        failure: function(e) {
                            ASSERT.fail("IO failure case.");
                        }
                    }
                });
                
                ASSERT.isNumber(id, "Expected interval id.");

                this.wait(function(){
                    ds.clearInterval(id);
                    this.wait(function(){
                        Y.Mock.verify(handler);
                    }, 1000);
                }, 1950);
            },

            testClearAll: function() {
                var ds = new Y.DataSource.Local();

                var handler = Y.Mock();
                Y.Mock.expect(handler,{
                    method: "handleSuccess",
                    args: [Y.Mock.Value.Any],
                    callCount: 3
                });

                ds.setInterval(500, {
                    callback: {
                        success: handler.handleSuccess,
                        failure: function(e) {
                            ASSERT.fail("IO failure case.");
                        }
                    }
                });
                ds.setInterval(500, {
                    callback: {
                        success: handler.handleSuccess,
                        failure: function(e) {
                            ASSERT.fail("IO failure case.");
                        }
                    }
                });
                ds.setInterval(500, {
                    callback: {
                        success: handler.handleSuccess,
                        failure: function(e) {
                            ASSERT.fail("IO failure case.");
                        }
                    }
                });

                this.wait(function(){
                    ds.clearAllIntervals();
                    this.wait(function(){
                        Y.Mock.verify(handler);
                    }, 500);
                }, 950);
            }
        });

        var suite = new Y.Test.Suite({name:"DataSource Test Suite"});
        suite.add(testClass);
        suite.add(testLocal);
        suite.add(testIO);
        suite.add(testGet);
        suite.add(testFunction);
        suite.add(testDataSchemaPlugin);
        suite.add(testCaching);
        suite.add(testPolling);

        Y.Test.Runner.setName("DataSource Test Runner");
        Y.Test.Runner.add(suite);
        Y.Test.Runner.run();
    });
})();
</script>
</body>
</html>
